package cn.topcodes.tcsf.app.service.impl;

import cn.topcode.unicorn.utils.CollectionUtil;
import cn.topcode.unicorn.utils.SpringContextHolder;
import cn.topcode.unicorn.utils.StringUtil;
import cn.topcode.unicorn.utils.UuidUtil;
import cn.topcodes.tcsf.app.domain.entity.AppClient;
import cn.topcodes.tcsf.admin.commons.generic.GenericService;
import cn.topcodes.tcsf.app.domain.entity.AppOperateLog;
import cn.topcodes.tcsf.app.domain.form.AppClientInfo;
import cn.topcodes.tcsf.app.event.ForceLogoutEvent;
import cn.topcodes.tcsf.app.service.AppClientService;
import cn.topcodes.tcsf.app.service.AppOperateLogService;
import cn.topcodes.tcsf.app.service.DailyActiveUsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;
import java.util.Date;
import java.util.List;

/**
 * APP客户端 服务
 * @author unicorn
 * @date 2017-11-13 22:06:58
 */
@Service
public class AppClientServiceImpl extends GenericService<AppClient> implements AppClientService {

    public static final String PUSH_TYPE_FORCED_LOGOUT = "PUSH_TYPE_FORCED_LOGOUT";

    @Autowired
    private DailyActiveUsersService dailyActiveUsersService;

    @Autowired
    private AppOperateLogService appOperateLogService;

    /**
     * 在指定app应用中获取app用户客户端信息
     * @param app       app
     * @param appUserId app用户ID
     * @return  app客户端信息
     */
    @Override
    public AppClient findBy(String app, Long appUserId) {
        Assert.hasText(app, "'app' cannot be blank");
        Assert.notNull(appUserId, "'appUserId' cannot be empty");
        Example example = this.buildExample();
        example.or().andEqualTo(AppClient.FIELD_APP, app)
                .andEqualTo(AppClient.FIELD_APP_USER_ID, appUserId);
        return this.findOne(example);
    }

    /**
     * 登录默认app客户端
     * @param appUserId app用户ID
     * @return   凭证
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public String loginDefaultApp(Long appUserId) {
        AppClient appClient = this.findBy(AppClient.APP_DEFAULT, appUserId);
        if(appClient == null) {
            appClient = new AppClient();
        }
        appClient.setAppUserId(appUserId);
        appClient.setToken(UuidUtil.getUUID());
        appClient.setApp(AppClient.APP_DEFAULT);
        appClient.setAppVersion(AppClient.APP_VERSION_UNKNOWN);
        appClient.setPlatform(AppClient.PLATFORM_UNKNOWN);
        appClient.setTerminal(AppClient.TERMINAL_UNKNOWN);
        appClient.setLastActiveTime(new Date());
        appClient.setLanguage("");
        this.save(appClient);

        dailyActiveUsersService.record(AppClient.APP_DEFAULT, appUserId);
        appOperateLogService.record(appUserId, "", AppOperateLog.TYPE_LOGIN, "User login");

        return appClient.getToken();
    }

    /**
     * 登录指定客户端信息
     * @param appUserId     app用户ID
     * @param appClientInfo app客户端信息
     * @return  token
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public String login(Long appUserId, AppClientInfo appClientInfo) {
        AppClient appClient = null;

        AppClient originClient = this.findBy(appClientInfo.getApp(), appUserId);
        String originToken = originClient != null ? originClient.getToken() : null;

        if (appClientInfo.isForceLogin()) {
            appClient = originClient;
        }
        if (appClient == null) {
            appClient = new AppClient();
        }
        if(StringUtil.isBlank(appClientInfo.getApp())) {
            appClient.setApp(AppClient.APP_DEFAULT);
        }else {
            appClient.setApp(appClientInfo.getApp());
        }
        if(appClientInfo.getLanguage() == null) {
            appClient.setLanguage("");
        }else {
            appClient.setLanguage(appClientInfo.getLanguage());
        }
        if(StringUtil.isBlank(appClientInfo.getAppVersion())) {
            appClient.setAppVersion(AppClient.APP_VERSION_UNKNOWN);
        }else {
            appClient.setAppVersion(appClientInfo.getAppVersion());
        }
        if(StringUtil.isBlank(appClientInfo.getPlatform())) {
            appClient.setPlatform(AppClient.PLATFORM_UNKNOWN);
        }else {
            appClient.setPlatform(appClientInfo.getPlatform());
        }
        if(StringUtil.isBlank(appClientInfo.getTerminal())) {
            appClient.setTerminal(AppClient.TERMINAL_UNKNOWN);
        }else {
            appClient.setTerminal(appClientInfo.getTerminal());
        }
        appClient.setLastActiveTime(new Date());
        appClient.setAppUserId(appUserId);
        appClient.setToken(UuidUtil.getUUID());
        this.save(appClient);

        ForceLogoutEvent event = new ForceLogoutEvent();
        event.setAppClient(appClient);
        event.setOriginToken(originToken);
        SpringContextHolder.publishEvent(event);

        dailyActiveUsersService.record(appClientInfo.getApp(), appUserId);
        appOperateLogService.record(appUserId, "", AppOperateLog.TYPE_LOGIN, "User login");

        return appClient.getToken();
    }

    /**
     * 退出默认APP
     * @param token 凭证
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void logoutDefaultApp(String token) {
        Assert.hasText(token, "'token' cannot be blank");
        Example example = this.buildExample();
        example.or().andEqualTo(AppClient.FIELD_APP, AppClient.APP_DEFAULT)
                .andEqualTo(AppClient.FIELD_TOKEN, token);
        this.deleteByExample(example);
    }

    /**
     * 退出指定app
     * @param app   app
     * @param token 凭证
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void logout(String app, String token) {
        Assert.hasText(app, "'app' cannot be blank");
        Assert.hasText(token, "'token' cannot be blank");
        Example example = this.buildExample();
        example.or().andEqualTo(AppClient.FIELD_APP, app)
                .andEqualTo(AppClient.FIELD_TOKEN, token);
        this.deleteByExample(example);
    }

    /**
     * 通过token查找
     * @param token 凭证
     * @return  app客户端信息
     */
    @Override
    public AppClient findByToken(String token) {
        Example example = this.buildExample();
        example.or().andEqualTo(AppClient.FIELD_TOKEN, token);
        return this.findOne(example);
    }

    /**
     * 查找该用户在默认app所有客户端信息
     * @param appUserId     app用户ID
     * @return      客户端信息列表
     */
    @Override
    public List<AppClient> getDefaultAppClients(Long appUserId) {
        Example example = this.buildExample();
        example.or().andEqualTo(AppClient.FIELD_APP_USER_ID, appUserId)
                .andEqualTo(AppClient.FIELD_APP, AppClient.APP_DEFAULT);
        return this.findAll(example);
    }

    /**
     * 查找该用户在默认app所有Token
     * @param appUserId     app用户ID
     * @return      Token信息列表
     */
    @Override
    public List<String> getDefaultAppTokens(Long appUserId) {
        List<AppClient> appClients = this.getDefaultAppClients(appUserId);
        return CollectionUtil.getPropList(appClients, AppClient.FIELD_TOKEN);
    }

    /**
     * 查找该用户在默认app的Token
     * @param appUserId app用户id
     * @return  token凭证
     */
    @Override
    public String getDefaultAppToken(Long appUserId) {
        List<String> tokens = this.getDefaultAppTokens(appUserId);
        if(tokens.isEmpty()) {
            return null;
        }
        return tokens.get(0);
    }

    /**
     * 获取指定app应用，用户的凭证
     * @param app   app
     * @param appUserId 用户id
     * @return  凭证
     */
    @Override
    public String getAppToken(String app, Long appUserId) {
        List<String> tokens = this.getAppTokens(app, appUserId);
        if(tokens.isEmpty()) {
            return null;
        }
        return tokens.get(0);
    }

    /**
     * 获取指定应用，app所有凭证
     * @param app       app
     * @param appUserId app用户ID
     * @return  凭证列表
     */
    @Override
    public List<String> getAppTokens(String app, Long appUserId) {
        Assert.hasText(app, "'app' cannot be blank");
        Assert.notNull(appUserId, "'appUserId' cannot be null");
        Example example = this.buildExample();
        example.or().andEqualTo(AppClient.FIELD_APP, app)
                .andEqualTo(AppClient.FIELD_APP_USER_ID, appUserId);
        List<AppClient> appClients = this.findAll(example);
        return CollectionUtil.getPropList(appClients, AppClient.FIELD_TOKEN);
    }

    @Override
    public List<AppClient> findByAppUserId(Long appUserId) {
        Example example = this.buildExample();
        example.or().andEqualTo(AppClient.FIELD_APP_USER_ID, appUserId);
        return this.findAll(example);
    }

    @Override
    public AppClient getAppClient(String app, Long appUserId) {
        List<AppClient> appClients = this.findByAppAndAppUserId(app, appUserId);
        if (CollectionUtils.isEmpty(appClients)) {
            return null;
        }
        return appClients.get(0);
    }

    @Override
    public List<AppClient> findByAppAndAppUserId(String app, Long appUserId) {
        Assert.hasText(app, "'app' cannot be blank");
        Assert.notNull(appUserId, "'appUserId' cannot be empty");
        Example example = this.buildExample();
        example.or().andEqualTo(AppClient.FIELD_APP, app)
                .andEqualTo(AppClient.FIELD_APP_USER_ID, appUserId);
        return this.findAll(example);
    }

    @Override
    public List<AppClient> findByAppAndAppUserIds(String app, List<Long> appUserIds) {
        Assert.hasText(app, "'app' cannot be blank");
        Assert.notEmpty(appUserIds, "'appUserIds' cannot be empty");
        Example example = this.buildExample();
        example.or().andEqualTo(AppClient.FIELD_APP, app)
                .andIn(AppClient.FIELD_APP_USER_ID, appUserIds);
        return this.findAll(example);
    }
}
